<?php

namespace common\service\pay;

use common\util\CurlInterface;
use common\util\Util;

/**
 * Class WxPayService
 * 微信交易接口调用核心
 * @package Base\Tool
 */
class WeChatPay
{
    public $unifiedOrderUrl = 'https://api.mch.weixin.qq.com/pay/unifiedorder';//统一下单API
    /************************手机浏览器内web支付**************************************/
    /**
     *
     */
    public function H5Pay($params)
    {
        $siteConfig = Util::getSiteConfig();
        if (empty($params['notify_url'])) {
            $params['notify_url'] = $siteConfig['notify_url'];
        }
        $data = array(
            'name' => $params['name'],//名称
            'order_id' => (string)$params['order_id'] . '_' . rand(1000, 9999),//支付ID
            'total_fee' => (string)$params['total_fee'] * 100,//总金
            'notify_url' => $params['notify_url'],//支付回调接口
            'trade_type' => 'MWEB',//用户的OPENID
            'scene_info' => [
                'h5_info' => [
                    'type' => 'Wap',
                    'wap_url' => $siteConfig['host_name'],
                    'wap_name' => $siteConfig['web_name']
                ]
            ]
        );
        $getpay = $this->unifiedOrderForWeChat($data);//统一下单API
        if ($getpay['flag'] == false) {
            return $getpay;
        }
        if (empty($getpay['data']['mweb_url'])) {
            return Util::returnArrEr('预支付会话异常！');
        }
        return Util::returnArrSu('', ['pay_url' => $getpay['data']['mweb_url']]);
    }
    /************************微信浏览器内web支付**************************************/
    /**
     * Function Description:去微信下单并获取返回
     * Function Name: unifiedOrderByOrderId
     * @param $params array
     * $order_id string 订单表 订单ID
     * $name string 产品名称
     * $total_fee int 总金额 单位分
     * $openid string 用户opendid
     * @return array
     *
     * @author nzf
     */
    public function webPay($params)
    {
        $siteConfig = Util::getSiteConfig();
        if (empty($params['notify_url'])) {
            $params['notify_url'] = $siteConfig['notify_url'];
        }
        $data = array(
            'name' => $params['name'],//名称
            'order_id' => (string)$params['order_id'] . '_' . rand(1000, 9999),//支付ID
            'total_fee' => (string)$params['total_fee'] * 100,//总金
            'notify_url' => $params['notify_url'],//支付回调接口
            'openid' => $params['openid']//用户的OPENID
        );
        $getPrepayId = $this->unifiedOrderForWeChat($data);//统一下单API
        if ($getPrepayId['flag'] == false) {
            return $getPrepayId;
        }
        //设置成功返回的结果数
        $wxPayConfig = Util::getWeChatConfig();
        $return = array(
            'appId' => $wxPayConfig['appid'],//微信�?放平台审核�?�过的应用APPID
            'package' => 'prepay_id=' . $getPrepayId['data']['prepay_id'],//微信返回的支付交易会话ID
            'nonceStr' => self::getNonceStr(),//随机字符�?
            'signType' => 'MD5',
            'timeStamp' => strval(time()),//当前时间�?
        );
        $return['paySign'] = self::getSign($return);
        return Util::returnArrSu('', array('payData' => $return, 'price' => $params['total_fee']));
    }

    /**
     * Function Description:统一下单API
     * Function Name: unifiedOrder
     * @param $params  array
     *     attach 附加数据，在查询API和支付知中原样返回，该字段主要用于商户携带订单的自定义数
     *     line_name 线路名称
     *     order_id 订单ID
     *     total_fee 总金
     *     notify_url 回调地址
     *
     * @return array
     *
     * @author nzf
     */
    public function unifiedOrderForWeChat($params)
    {
        $wxPayConfig = Util::getWeChatConfig();
        $data = array(
            'appid' => $wxPayConfig['appid'],//微信开放平台审核过的应用APPID
            'attach' => empty($params['attach']) ? '' : $params['attach'],
            'body' => $params['name'],//产品名称
            'mch_id' => $wxPayConfig['mch_id'],//商户微信支付分配的商户号
            'nonce_str' => $this->getNonceStr(),//随机字符
            'notify_url' => $params['notify_url'],//通知地址
            'out_trade_no' => $params['order_id'],//商户订单ID加上当前时间
            'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],//用户端实际ip
            'total_fee' => $params['total_fee'],//订单总金额，单位为分
            'trade_type' => empty($params['trade_type']) ? 'JSAPI' : $params['trade_type'],//交易类型
        );
        if (empty($params['openid']) == false) {//存在openid
            $data['openid'] = $params['openid'];
        }
        if (isset($params['scene_info'])) {
            $data['scene_info'] = json_encode($params['scene_info']);
        }
        $data['sign'] = $this->getSign($data);//交易签名
        $curl = new CurlInterface($data, 2);//函数
        $curl->setBaseUrl($this->unifiedOrderUrl);
        $result = $curl->execute('', 'POST');
        if (empty($result['prepay_id'])) {
            return Util::returnArrEr('预支付交易会话异常！');
        }
        return Util::returnArrSu('', array('prepay_id' => $result['prepay_id'], 'mweb_url' => empty($result['mweb_url']) ? '' : $result['mweb_url']));
    }
    /************************扫描支付**************************************/

    /**
     * Function Description:去微信下单并获取返回
     * Function Name: unifiedOrderByOrderId
     * @param $par
     * @return array
     *
     * @author nzf
     */
    public function unifiedOrderByOrderIdForSao($par)
    {
        $siteConfig = Util::getSiteConfig();
        $notify_url = $siteConfig['host_name'] . $siteConfig['notify_url'];
        $data = array(
            'name' => $par['name'],//线路名称
            'order_id' => (string)$par['order_id'] . '_' . rand(100, 999),//订单ID
            'total_fee' => $par['total_fee'] * 100,//总金
            'notify_url' => $notify_url
        );
        $codUrl = $this->unifiedOrderForSao($data);//统一下单API
        if ($codUrl['flag'] == false) {
            return $codUrl;
        }
        //设置成功返回的结果数�?
        $url = $siteConfig['host_name'] . '/fx/?r=weChat/we-chat/q-code&qCode=' . urlencode($codUrl['data']['code_url']) . '&_math=' . rand(100, 999);
        return Util::returnArrSu('', array('codUrl' => $url, 'price' => $par['total_fee']));
    }

    /**
     * Function Description:统一下单API
     * Function Name: unifiedOrder
     * @param $params  array
     *     attach 附加数据，在查询API和支付知中原样返回，该字段主要用于商户携带订单的自定义数
     *     line_name 线路名称
     *     order_id 订单ID
     *     total_fee 总金
     *     notify_url 回调地址
     *
     * @return array
     *
     * @author 倪宗�?
     */
    public function unifiedOrderForSao($params)
    {
        $wxPayConfig = Util::getWeChatConfig();
        $data = array(
            'appid' => $wxPayConfig['appid'],//微信�?放平台审核�?�过的应用APPID
            'mch_id' => $wxPayConfig['mch_id'],//商户�? 微信支付分配的商户号
            'nonce_str' => $this->getNonceStr(),//随机字符�?
            'body' => $params['name'],//线路名称 �? 上订单ID
            'out_trade_no' => $params['order_id'],//商户订单ID加上当前时间
            'total_fee' => $params['total_fee'],//订单总金额，单位为分
            'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],//用户端实际ip
            'notify_url' => $params['notify_url'],//通知地址
            'trade_type' => 'NATIVE',//交易类型
        );
        $data['sign'] = $this->getSign($data);//交易签名
        $curl = new CurlInterface($data, 2);//函数�?
        $curl->setBaseUrl($this->unifiedOrderUrl);
        $result = $curl->execute('', 'POST');
        if (empty($result['prepay_id'])) {
            return Util::returnArrEr('预支付交易会话异常！');
        }
        return Util::returnArrSu('', array('prepay_id' => $result['prepay_id'], 'code_url' => $result['code_url']));
    }

    /***************************************退款****************************************/

    /**
     * Des:微信退款接口
     * Name: cancelOrder
     * @param $params
     * @return array
     * @author 倪宗锋
     */
    public static function cancelOrder($params)
    {
        $config = Util::getWeChatConfig($params['app_id']);
        $arr = array(
            'appid' => $config['appid'],
            'mch_id' => $config['mch_id'],
            'nonce_str' => static::getNonceStr(),
            'out_trade_no' => (string)$params['order_id'],//订单ID
            'out_refund_no' => (string)date('YmdHis') . rand(100, 999),//退款ID
            'total_fee' => (string)$params['total_fee'] * 100,//订单总金额 元
            'refund_fee' => (string)$params['refund_fee'] * 100,//退款金额 元
            'op_user_id' => $config['mch_id']
        );
        $arr['sign'] = static::getSign($arr);
        $curl = new CurlInterface($arr, 2);//函数类
        $curl->setCert($config);
        $curl->setBaseUrl('https://api.mch.weixin.qq.com/secapi/pay/refund');
        $result = $curl->execute('', 'POST');
        if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') {
            return Util::returnArrSu();
        }
        $msg = $result['return_msg'];
        if ($msg == 'OK') {
            $msg = $result['err_code_des'];
        }
        return Util::returnArrEr('退款失败！' . $msg);

    }

    /*************************************通用方法**************************************/
    /**
     * Des:检测是否已经支付
     * Name: checkIsPay
     * @param $orderId
     * @return array
     * @author 倪宗锋
     */
    public static function checkIsPay($orderId)
    {
        $config = Util::getWeChatConfig();
        $arr = array(
            'appid' => $config['appid'],
            'mch_id' => $config['mch_id'],
            'out_trade_no' => (string)$orderId,//订单ID
            'nonce_str' => static::getNonceStr(),
        );
        $arr['sign'] = static::getSign($arr);
        $curl = new CurlInterface($arr, 2);//函数类
        $curl->setCert($config);
        $curl->setBaseUrl('https://api.mch.weixin.qq.com/pay/orderquery');
        $result = $curl->execute('', 'POST');
        if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') {
            return Util::returnArrSu('', $result);
        }
        $msg = $result['return_msg'];
        if ($msg == 'OK') {
            $msg = $result['err_code_des'];
        }
        return Util::returnArrEr('退款失败！' . $msg);
    }

    /**
     * Function Description:获取签名
     * Function Name: getSign
     * @param $params
     * @return string
     *
     * @author nzf
     */
    public static function getSign($params)
    {
        if (isset($params['sign'])) {
            unset($params['sign']);
        }
        $config = Util::getWeChatConfig();
        //签名步骤按字典序排序参
        ksort($params);
        $string = self::ToUrlParams($params);
        //签名步骤二：在string后加入KEY
        $string = $string . "&key=" . $config['key'];
        //签名步骤三：MD5加密
        $string = md5($string);
        //签名步骤四：有字符转为大
        $result = strtoupper($string);
        return $result;

    }

    /**
     * Function Description:格式化参�? 格式化成url参数
     * Function Name: ToUrlParams
     * @param $params
     *
     * @return string
     *
     * @author 倪宗�?
     */
    public static function ToUrlParams($params)
    {
        $buff = "";
        foreach ($params as $k => $v) {
            if ($k != "sign" && $v != "" && !is_array($v)) {
                $buff .= $k . "=" . $v . "&";
            }
        }
        $buff = trim($buff, "&");
        return $buff;
    }

    /**
     * Function Description:产生的随机字符串 不长
     * Function Name: getNonceStr
     * @param int $length
     *
     * @return string
     *
     * @author 倪宗�?
     */
    public static function getNonceStr($length = 32)
    {
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
        $str = "";
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }
}